# -*- coding:utf-8 -*-
# business/business_chain.py

from sanic.log import logger
from sqlalchemy import select, and_

from model.model_result import DataResult
from model.models import AppSystem, BusinessChain, BusinessScenario


async def get_business_chain(request):
    """
    获取所有应用系统业务链列表
    """
    data_result = DataResult()
    session = request.ctx.session
    try:
        busi_chain_list = []
        async with session.begin():
            query_busi_chain = select(
                BusinessChain.chain_uuid,
                BusinessChain.sys_id,
                BusinessChain.sys_sn,
                BusinessChain.business_scenario_id,
                AppSystem.app_system_id,
                AppSystem.sys_name,
                BusinessScenario.name.label('business_scenario_name')
            ).outerjoin(
                AppSystem,
                AppSystem.sys_id == BusinessChain.sys_id
            ).outerjoin(
                BusinessScenario,
                BusinessScenario.business_scenario_id == BusinessChain.business_scenario_id
            )
            result = await session.execute(query_busi_chain)
            rows = result.all()
            busi_chain_list = [row._asdict() for row in rows]

        busi_chain_info = {}
        # 构造数据格式: [
        #   {"chain_uuid": "", "business_scenario_id": "", "business_scenario_name": "", "app_sys_chain": []}
        # ]
        for bc in busi_chain_list:
            chain_uuid = bc.pop('chain_uuid')
            business_scenario_id = bc.pop('business_scenario_id')
            business_scenario_name = bc.pop('business_scenario_name')
            if not busi_chain_info.get(chain_uuid):
                busi_chain_info[chain_uuid] = {
                    "chain_uuid": chain_uuid,
                    "business_scenario_id": business_scenario_id,
                    "business_scenario_name": business_scenario_name,
                    "app_sys_chain": []
                }
            busi_chain_info[chain_uuid]['app_sys_chain'].append(bc)
        busi_chain_list = list(busi_chain_info.values())
        logger.debug(f"get business_chain: {busi_chain_list}")
        data_result.data["items"] = busi_chain_list
        data_result.message = "获取所有应用系统业务链列表成功"
    except Exception as ex:
        data_result.status = False
        data_result.code = 400
        data_result.message = "获取所有应用系统业务链列表失败"
        logger.exception(ex)
    return data_result


async def get_business_chain_by_uuid(chain_uuid, request):
    """
    根据业务链UUID查询应用系统业务链
    """
    if not chain_uuid:
        raise Exception('缺少应用系统业务链UUID(chain_uuid)参数值!')
    data_result = DataResult()
    session = request.ctx.session
    try:
        busi_chain_list = []
        async with session.begin():
            query_busi_chain = select(
                # BusinessChain.chain_uuid,
                BusinessChain.sys_id,
                BusinessChain.sys_sn,
                BusinessChain.business_scenario_id,
                AppSystem.app_system_id,
                AppSystem.sys_name,
                BusinessScenario.name.label('business_scenario_name')
            ).outerjoin(
                AppSystem,
                AppSystem.sys_id == BusinessChain.sys_id
            ).outerjoin(
                BusinessScenario,
                BusinessScenario.business_scenario_id == BusinessChain.business_scenario_id
            ).where(
                BusinessChain.chain_uuid == chain_uuid
            )
            result2 = await session.execute(query_busi_chain)
            rows = result2.all()
            busi_chain_list = [row._asdict() for row in rows]

        busi_chain_info = {}
        # 构造数据格式: [
        #   {"chain_uuid": "", "business_scenario_id": "", "business_scenario_name": "", "app_sys_chain": []}
        # ]
        for bc in busi_chain_list:
            business_scenario_id = bc.pop('business_scenario_id')
            business_scenario_name = bc.pop('business_scenario_name')
            if not busi_chain_info.get(chain_uuid):
                busi_chain_info = {
                    "chain_uuid": chain_uuid,
                    "business_scenario_id": business_scenario_id,
                    "business_scenario_name": business_scenario_name,
                    "app_sys_chain": []
                }
            busi_chain_info['app_sys_chain'].append(bc)
        logger.debug(f"get business_chain list by chain_uuid {chain_uuid}, res: {busi_chain_info}")
        data_result.data = busi_chain_info
        data_result.message = "根据业务链UUID查询应用系统业务链列表成功"
    except Exception as ex:
        data_result.status = False
        data_result.code = 400
        data_result.message = "根据业务链UUID查询应用系统业务链列表失败"
        logger.exception(ex)
    return data_result


async def get_business_chain_by_app_sys_id(app_sys_id, request):
    """
    根据应用系统ID查询相关应用系统所有业务链
    """
    if not app_sys_id:
        raise Exception('缺少应用系统ID(app_sys_id)参数值!')
    data_result = DataResult()
    session = request.ctx.session
    try:
        # 查询应用系统相关业务链和业务场景信息
        busi_chain_list = []
        async with session.begin():
            query_busi_chain_1 = select(
                BusinessChain.chain_uuid,
                BusinessChain.sys_id,
                BusinessChain.sys_sn,
                BusinessChain.business_scenario_id,
                # AppSystem.app_system_id,
                # AppSystem.sys_name,
                BusinessScenario.name.label('business_scenario_name')
            # ).outerjoin(
            #     AppSystem,
            #     AppSystem.sys_id == BusinessChain.sys_id
            ).outerjoin(
                BusinessScenario,
                BusinessScenario.business_scenario_id == BusinessChain.business_scenario_id
            ).where(
                BusinessChain.sys_id == app_sys_id
            )
            result1 = await session.execute(query_busi_chain_1)
            rows = result1.all()
            busi_chain_list = [row._asdict() for row in rows]
            logger.debug(f"select app business chain res: {busi_chain_list}")

        # 查询应用系统相关业务链信息
        app_busi_chain_uuids = [bc['chain_uuid'] for bc in busi_chain_list]
        async with session.begin():
            query_busi_chain_2 = select(
                BusinessChain.chain_uuid,
                BusinessChain.sys_id,
                BusinessChain.sys_sn,
                AppSystem.app_system_id,
                AppSystem.sys_name,
            ).outerjoin(
                AppSystem,
                AppSystem.sys_id == BusinessChain.sys_id
            ).where(
                BusinessChain.chain_uuid.in_(app_busi_chain_uuids)
            )
            result = await session.execute(query_busi_chain_2)
            rows = result.all()
            app_busi_chain_list = [row._asdict() for row in rows]
            logger.debug(f"select app global business chain res: {app_busi_chain_list}")

        # 构造数据格式: [
        #   {chain_uuid: [app_sys_chain]}
        # ]
        app_busi_chain_info = {}
        for abc in app_busi_chain_list:
            chain_uuid = abc.pop('chain_uuid')
            if not app_busi_chain_info.get(chain_uuid):
                app_busi_chain_info[chain_uuid] = []
            app_busi_chain_info[chain_uuid].append(abc)

        busi_chain_info = {}
        # 构造数据格式: [
        #   {"chain_uuid": "", "business_scenario_id": "", "business_scenario_name": "", "app_sys_chain": []}
        # ]
        for bc in busi_chain_list:
            chain_uuid = bc.pop('chain_uuid')
            business_scenario_id = bc.pop('business_scenario_id')
            business_scenario_name = bc.pop('business_scenario_name')
            if not busi_chain_info.get(chain_uuid):
                busi_chain_info[chain_uuid] = {
                    "chain_uuid": chain_uuid,
                    "business_scenario_id": business_scenario_id,
                    "business_scenario_name": business_scenario_name,
                    "app_sys_chain": app_busi_chain_info.get(chain_uuid, [])
                }

        busi_chain_list = list(busi_chain_info.values())
        logger.debug(f"get business_chain list by AppSystem.sys_id {app_sys_id}, res: {busi_chain_list}")
        data_result.data["items"] = busi_chain_list
        data_result.message = "根据应用系统ID查询相关应用系统所有业务链列表成功"
    except Exception as ex:
        data_result.status = False
        data_result.code = 400
        data_result.message = "根据应用系统ID查询相关应用系统所有业务链列表失败"
        logger.exception(ex)
    return data_result


async def get_association_system_by_app_sys_id(app_sys_id, request):
    """
    根据应用系统ID查询所有业务链中上下游关联应用系统
    """
    if not app_sys_id:
        raise Exception('缺少应用系统ID(app_sys_id)参数值!')
    data_result = DataResult()
    session = request.ctx.session
    try:
        # 查询应用系统基本信息
        app_sys_info = {}
        async with session.begin():
            query_app_sys = select(
                AppSystem.app_system_id,
                AppSystem.sys_id,
                AppSystem.sys_name,
            ).where(
                AppSystem.sys_id == app_sys_id,
                AppSystem.is_deleted == 0
            )
            result = await session.execute(query_app_sys)
            app_sys_info = result.mappings().one_or_none()

        if not app_sys_info:
            raise Exception(f"根据系统ID({app_sys_id})查找应用系统未找到或已删除!")

        # 查询应用系统相关业务链信息
        busi_chain_list = []
        async with session.begin():
            query_busi_chain_1 = select(
                BusinessChain.chain_uuid,
                BusinessChain.sys_id,
                BusinessChain.sys_sn,
            ).where(
                BusinessChain.sys_id == app_sys_id
            )
            result1 = await session.execute(query_busi_chain_1)
            rows = result1.all()
            busi_chain_list = [row._asdict() for row in rows]
            logger.debug(f"select app business chain res: {busi_chain_list}")

        # 查询应用系统相关业务链和业务场景信息
        app_busi_chain_uuids = [bc['chain_uuid'] for bc in busi_chain_list]
        async with session.begin():
            query_busi_chain_2 = select(
                BusinessChain.chain_uuid,
                BusinessChain.sys_id,
                BusinessChain.sys_sn,
                AppSystem.app_system_id,
                AppSystem.sys_name,
                BusinessChain.business_scenario_id,
                BusinessScenario.name.label('business_scenario_name')
            ).outerjoin(
                AppSystem, and_(
                    AppSystem.sys_id == BusinessChain.sys_id,
                    AppSystem.is_deleted == 0
                )
            ).outerjoin(
                BusinessScenario,
                BusinessScenario.business_scenario_id == BusinessChain.business_scenario_id
            ).where(
                BusinessChain.chain_uuid.in_(app_busi_chain_uuids)
            )
            result = await session.execute(query_busi_chain_2)
            rows = result.all()
            app_busi_chain_list = [row._asdict() for row in rows]
            logger.debug(f"select app global business chain res: {app_busi_chain_list}")

        # 构造数据格式: [
        #   {chain_uuid-sys_sn: {app_sys_busi_chain_info}}
        # ]
        app_busi_chain_sn_dict = {}
        for abc in app_busi_chain_list:
            chain_uuid = abc.pop('chain_uuid')
            sys_sn = abc['sys_sn']
            cu_sn = f"{chain_uuid}-{sys_sn}"
            app_busi_chain_sn_dict[cu_sn] = abc

        app_system_info = {
            'app_system_id': app_sys_info['app_system_id'],
            'app_sys_id': app_sys_info['sys_id'],
            'app_sys_name': app_sys_info['sys_name'],
            'upstream': [],
            'downstream': []
        }
        # 构造数据格式
        # {
        #     'app_system_id': "",
        #     'app_sys_id': "",
        #     'app_sys_name': "",
        #     'upstream': [
        #         {
        #             'chain_uuid': "",
        #             'business_scenario_id': "",
        #             'business_scenario_name': "",
        #             'app_system_id': ''
        #             'sys_id': "",
        #             'sys_sn': "",
        #             'sys_name': ""
        #         }
        #     ],
        #     'downstream': [
        #         {
        #             'chain_uuid': "",
        #             'business_scenario_id': "",
        #             'business_scenario_name': "",
        #             'app_system_id': ''
        #             'sys_id': "",
        #             'sys_sn': "",
        #             'sys_name': ""
        #         }
        #     ]
        # }
        for bc in busi_chain_list:
            chain_uuid = bc.pop('chain_uuid')
            sys_sn = bc['sys_sn']
            up_cu_sn = f"{chain_uuid}-{sys_sn - 1}"
            down_cu_sn = f"{chain_uuid}-{sys_sn + 1}"
            if app_busi_chain_sn_dict.get(up_cu_sn):
                app_system_info['upstream'].append(app_busi_chain_sn_dict[up_cu_sn])
            if app_busi_chain_sn_dict.get(down_cu_sn):
                app_system_info['downstream'].append(app_busi_chain_sn_dict[down_cu_sn])

        # 去重复
        deduplication = lambda lst: [dict(d) for d in list(set(tuple(d.items()) for d in lst))]
        app_system_info['upstream'] = deduplication(app_system_info['upstream'])
        app_system_info['downstream'] = deduplication(app_system_info['downstream'])

        logger.debug(f"get business_chain list by AppSystem.sys_id {app_sys_id}, res: {busi_chain_list}")
        data_result.data = app_system_info
        data_result.message = "根据应用系统ID查询相关应用系统所有业务链列表成功"
    except Exception as ex:
        data_result.status = False
        data_result.code = 400
        data_result.message = "根据应用系统ID查询相关应用系统所有业务链列表失败"
        logger.exception(ex)
    return data_result
